package com.xyzh.application.base.service;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;

import com.xyzh.application.base.entity.BasicEntity;
import com.xyzh.application.common.annotations.*;
import com.xyzh.application.common.constants.ReqPage;
import com.xyzh.application.common.exceptionHandler.DatabaseAccessException;
import com.xyzh.application.common.util.ResultHelper;

import com.xyzh.application.common.util.SecurityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.*;

import com.xyzh.application.base.dao.BasicMapper;

public class BasicServiceImpl<M extends BasicMapper<T>, T> extends ServiceImpl<M, T> implements BasicService<T> {


    @Value("${system.super-admin.account:superadmin}")
    private String systemSuperAdminAccount;

    /**
     * 用于单表查询，如果对象属性值不为空，则添加到where条件中：string-->like，其他-->eq
     *
     * @param t
     * @param isAsc
     * @param orderBy
     * @return
     */
    @Override
    public List<T> listLike(T t, boolean isAsc, String orderBy) {
        return this.getBaseMapper().selectList(this.getLikeQueryWrapper(t).orderBy(true, isAsc, orderBy));
    }

    @Override
    public List<T> listLike(T t, boolean isAsc, String orderBy, String... orderBys) {
        return this.getBaseMapper().selectList(this.getLikeQueryWrapper(t).orderBy(true, isAsc, orderBy, orderBys));
    }

    /**
     * 用于单表查询，如果对象属性值不为空，则添加到where条件中：条件均为eq
     *
     * @param t
     * @param isAsc
     * @param orderBy
     * @return
     */
    @Override
    public List<T> list(T t, boolean isAsc, String orderBy) {
        return this.getBaseMapper().selectList(this.getEqQueryWrapper(t).orderBy(true, isAsc, orderBy));
    }

    @Override
    public List<T> list(T t, boolean isAsc, String orderBy, String... orderBys) {
        return this.getBaseMapper().selectList(this.getEqQueryWrapper(t).orderBy(true, isAsc, orderBy, orderBys));
    }

    /**
     * 列表精准查询
     *
     * @param t
     * @return
     */
    @Override
    public List<T> list(T t) {
        return this.getBaseMapper().selectList(this.getEqQueryWrapper(t));
    }

    @Override
    public boolean updateEntity(T entity) {
        this.beforeUpdate(entity);
        boolean flag;
        if (this.hasMultiId(entity)) {
            flag = this.updateByMultiId(entity);
        } else {
            flag = super.updateById(entity);
        }

        return flag;

    }


    @Override
    public boolean updateEntityNotNull(T entity) {
        this.beforeUpdate(entity);
        boolean flag;
        if (this.hasMultiId(entity)) {
            flag = this.updateNotNullByMultiId(entity);
        } else {
            flag = this.updateNotNullById(entity);
        }
//        if (flag){
//            doLog(entity, SysLogEntity.LOG_TYPE_UPDATE);
//        }
        return flag;
    }

    private void beforeUpdate(T t) {
        if (t instanceof BasicEntity) {
            BasicEntity entity = (BasicEntity) t;
//            entity.setUpdateby(this.getLocalUserId());
//            entity.setUpdatetime(new Date());
        }
    }


    @Override
    public boolean deleteEntity(T entity) {
        boolean flag;
        if (this.hasMultiId(entity)) {
            flag = this.deleteByMultiId(entity);
        } else {
            flag = this.deleteById(entity);
        }
        return flag;
    }

    @Override
    public boolean deleteEntityNotId(T entity){
        QueryWrapper<T> queryWrapper=this.getEqQueryWrapper(entity);
        if(queryWrapper.isEmptyOfWhere()){
            return false;
        }
        return  super.remove(queryWrapper);

    }


    @Override
    public String deleteBatchEntity(List<T> list) {
        int success = 0;
        int fail = 0;
        for (T entity : list) {
            boolean flag;
            if (this.hasMultiId(entity)) {
                flag = this.deleteByMultiId(entity);
            } else {
                flag = this.deleteById(entity);
            }
            if (flag) {
                success++;
            } else {
                fail++;
            }
        }
//      doLog(entity, SysLogEntity.LOG_TYPE_DELETE);
        return "成功删除" + success + "条，失败" + fail + "条!";
    }

    @Override
    public boolean saveEntity(T t)  {
        this.toUpperCase(t);
        this.beforeSave(t);
        boolean flag = super.save(t);

        return flag;
    }

    @Override
    public boolean saveEntityNotCheck(T t) {
        this.toUpperCase(t);
        if (t instanceof BasicEntity) {
            BasicEntity entity = (BasicEntity) t;
//            if (StrUtil.isEmpty(entity.getCreateby())) {
//                entity.setCreateby(this.getLocalUserId());
//            }
//            if (ObjectUtil.isEmpty(entity.getCreatetime())) {
//                entity.setCreatetime(new Date());
//            }
        }
        boolean flag = super.save(t);
//        if (flag) {
//            doLog(entity, SysLogEntity.LOG_TYPE_INSERT);
//        }
        return flag;
    }

    /**
     * 查询实体个数
     *
     * @param t
     * @return
     */
    @Override
    public long countEntity(T t) {
        if (this.hasMultiId(t)) {
            return checkMultiUnique(t);
        }
        return queryEntityCount(t);
    }

    /**
     * 查询实体个数，使用于@UniqueCheck注解
     *
     * @param t
     * @return
     */
    @Override
    public long queryEntityCount(T t) {
        QueryWrapper<T> queryWrapper= this.getQueryWrapperForUniqueCheck(t);
        if(queryWrapper.isEmptyOfWhere()){
            return 0;
        }else {
            return this.count(queryWrapper);
        }
    }

    private QueryWrapper<T> getQueryWrapperForUniqueCheck(T t) {
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(t.getClass());
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        List<Field> fields = this.getWrapperField(t);
        for (Field f : fields) {
            try {
                UniqueCheck objUniqueCheck = f.getAnnotation(UniqueCheck.class);
                if (objUniqueCheck != null) {
                    f.setAccessible(true);
                    Object value = f.get(t);
                    if (value == null || "".equals(value)) {
                        continue;
                    }
                    if (f.getAnnotation(UpperCase.class) != null) {
                        value = value.toString().toUpperCase();
                    }
                    ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                    if (columnCache != null) {
                        queryWrapper.eq(columnCache.getColumn(), value);
                    }
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
//        if (queryWrapper.isEmptyOfWhere()) {
//            throw new DatabaseAccessException("唯一性检查时传参不能为空");
//        }
        return queryWrapper;
    }

    /**
     * 复合主键详情查询
     *
     * @param entity
     * @return
     */
    @Override
    public T selectByMultiId(T entity) {
        return this.getBaseMapper().selectOne(this.getMultiIdQueryWrapper(entity));
    }


    @Override
    public T selectById(Serializable id) {
        return this.getBaseMapper().selectById(id);
    }

    /**
     * 复合主键单条删除
     *
     * @param entity
     * @return
     */
    private boolean deleteByMultiId(T entity) {
        this.toUpperCase(entity);
        int count = this.getBaseMapper().delete(this.getMultiIdQueryWrapper(entity));
        return count > 0;
    }


    private boolean hasMultiId(T t) {
        List<Field> fields = this.getWrapperField(t);
        for (Field f : fields) {
            TableMultiId tableMultiId = f.getAnnotation(TableMultiId.class);
            if (tableMultiId != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * 复合主键批量删除
     *
     * @param entitys
     * @return
     */
    @Override
    public boolean deleteBatchByMultiId(List<T> entitys) {
        List<QueryWrapper<T>> list = this.getMultiIdQueryWrapperByList(entitys);
        if (list == null) {
            return false;
        }
        int count = 0;
        for (int i = 0; i < list.size(); i++) {
            count += this.getBaseMapper().delete(list.get(i));
//            if (count > 0) {
//                doLog(entitys.get(i), SysLogEntity.LOG_TYPE_DELETE);
//            }
        }
        return count > 0;
    }

    /**
     * 复合主键修改
     *
     * @param entity
     * @return
     */
    private boolean updateByMultiId(T entity) {
        this.toUpperCase(entity);
        int count = this.getBaseMapper().update(entity, this.getMultiIdQueryWrapper(entity));
        return count > 0;
    }

    private boolean updateNotNullByMultiId(T entity) {
        this.toUpperCase(entity);
        return this.getBaseMapper().update(null, this.getUpdateWrapper(entity, true)) > 0;
    }


    private boolean updateNotNullById(T entity) {
        this.toUpperCase(entity);
        return this.getBaseMapper().update(null, this.getUpdateWrapper(entity, false)) > 0;
    }

    /**
     * 复合主键批量修改
     *
     * @param entitys
     * @return
     */
    @Override
    public boolean updateBatchByMultiId(List<T> entitys) {
        List<QueryWrapper<T>> list = this.getMultiIdQueryWrapperByList(entitys);
        if (list == null) {
            return false;
        }
        int count = 0;
        for (int i = 0; i < list.size(); i++) {
            count += this.getBaseMapper().update(this.toUpperCase(entitys.get(i)), list.get(i));
        }
        return count > 0;
    }


    @Override
    public Integer queryMaxSortkey(String table) {

        Integer maxSortkey =this.getBaseMapper().selectMaxSortkey(table);
        if (maxSortkey == null) {
            return 0;
        }
        return maxSortkey;
    }

    private boolean deleteById(T t) {
        return super.remove(this.getIdQueryWrapper(t));
    }

    /**
     * 保存前的操作
     *
     * @param t
     */
    private void beforeSave(T t) {
        long count = this.countEntity(t);
        if (count > 0) {
            throw new DuplicateKeyException("必要字段重复");
        }
        count=checkByEq(t);
        if(count>0){
            throw new DuplicateKeyException("存在相同数据");
        }
        if (t instanceof BasicEntity) {
            BasicEntity entity = (BasicEntity) t;
//            if (StrUtil.isEmpty(entity.getCreateby())) {
//                entity.setCreateby(this.getLocalUserId());
//            }
//
//            if (ObjectUtil.isEmpty(entity.getCreatetime())) {
//                entity.setCreatetime(new Date());
//            }


        }
    }


    private T toUpperCase(T t) {
        List<Field> fields = this.getWrapperField(t);
        for (Field f : fields) {
            try {
                f.setAccessible(true);
                Object value = f.get(t);
                if (f.getAnnotation(UpperCase.class) != null && f.getType() == String.class) {
                    if (value == null || "".equals(value)) {
                        continue;
                    }
                    if (f.getAnnotation(UpperCase.class) != null) {
                        value = value.toString().toUpperCase();
                    }
                    f.set(t, value);
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return t;
    }

    private long checkMultiUnique(T entity) {
        return this.count(this.getMultiIdQueryWrapper(entity));
    }

    private long checkByEq(T entity) {
        return this.count(this.getEqQueryWrapper(entity));
    }

    /**
     * 分页查询
     *
     * @param reqPage
     * @return
     */
    @Override
    public ResultHelper queryByPage(ReqPage<T> reqPage) {
        if (reqPage.export()) {
            //说明不分页
            List<T> list = this.baseMapper.selectList(this.getEqQueryWrapper(reqPage.getData()));
            return this.create(list, reqPage);
        }
        //下面是分页
        Page<T> page = new Page<>(reqPage.getPageCurrent(), reqPage.getPageSize());
        return execQueryByPage(page, reqPage.getData());
    }

    private ResultHelper create(List<T> list, ReqPage<T> reqPage) {
        return ResultHelper.succeed(list);

    }

    private ResultHelper execQueryByPage(Page<T> page, T t) {
        this.page(page, this.getEqQueryWrapper(t));
        return ResultHelper.succeed(page);
    }

    @Override
    public ResultHelper queryByPage(ReqPage<T> reqPage, OrderItem... orderItems) {
        Page<T> page = new Page<>(reqPage.getPageCurrent(), reqPage.getPageSize());
        page.addOrder(orderItems);
        return execQueryByPage(page, reqPage.getData());
    }

    @Override
    public ResultHelper queryLikeByPage(ReqPage<T> reqPage) {
        Page<T> page = new Page<>(reqPage.getPageCurrent(), reqPage.getPageSize());
        return execLikeByPage(page, reqPage.getData());
    }

    private ResultHelper execLikeByPage(Page<T> page, T t) {
        this.page(page, this.getLikeQueryWrapper(t));

        return ResultHelper.succeed(page);
    }

    @Override
    public ResultHelper queryLikeByPage(ReqPage<T> reqPage, OrderItem... orderItems) {
        Page<T> page = new Page<>(reqPage.getPageCurrent(), reqPage.getPageSize());
        page.addOrder(orderItems);
        return execLikeByPage(page, reqPage.getData());
    }

    /**
     * 根据id查找
     * @param t
     * @return
     */
    private QueryWrapper<T> getIdQueryWrapper(T t) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        List<Field> fields = this.getWrapperField(t);
        for (Field f : fields) {
            try {
                TableId tableId = f.getAnnotation(TableId.class);
                if (tableId != null) {
                    f.setAccessible(true);
                    Object value = f.get(t);
                    if (value != null && f.getAnnotation(UpperCase.class) != null) {
                        value = value.toString().toUpperCase();
                    }
                    queryWrapper.eq(tableId.value(), value);
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return queryWrapper;
    }

    /**
     * 构建组合主键精准查询
     *
     * @param t
     * @return
     */
    private QueryWrapper<T> getMultiIdQueryWrapper(T t) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        List<Field> fields = this.getWrapperField(t);
        for (Field f : fields) {
            try {
                TableMultiId tableMultiId = f.getAnnotation(TableMultiId.class);
                if (tableMultiId != null) {
                    f.setAccessible(true);
                    Object value = f.get(t);
                    if (value != null && f.getAnnotation(UpperCase.class) != null) {
                        value = value.toString().toUpperCase();
                    }
                    queryWrapper.eq(tableMultiId.value(), value);
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return queryWrapper;
    }

    /**
     * 组装联合主键的条件列表
     *
     * @param entitys
     * @return
     */
    private List<QueryWrapper<T>> getMultiIdQueryWrapperByList(List<T> entitys) {
        if (CollectionUtils.isEmpty(entitys)) {
            return null;
        }
        List<QueryWrapper<T>> list = Lists.newArrayList();
        List<Field> fields = this.getWrapperField(entitys.get(0));
        entitys.forEach(entity -> {
            QueryWrapper<T> queryWrapper = new QueryWrapper<>();
            for (Field f : fields) {
                try {
                    TableMultiId tableMultiId = f.getAnnotation(TableMultiId.class);
                    if (tableMultiId != null) {
                        f.setAccessible(true);
                        Object value = f.get(entity);
                        if (value != null && f.getAnnotation(UpperCase.class) != null) {
                            value = value.toString().toUpperCase();
                        }
                        queryWrapper.eq(tableMultiId.value(), value);
                    }
                } catch (IllegalAccessException e) {
                    log.error(e.getMessage());
                }
            }
            list.add(queryWrapper);
        });
        return list;
    }

    /**
     * 构建条件查询,精准查询
     *
     * @param t
     * @return
     */
    private QueryWrapper<T> getEqQueryWrapper(T t) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        List<Field> fields = this.getWrapperField(t);
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(t.getClass());
        for (Field f : fields) {
            try {
                f.setAccessible(true);
                Object value = f.get(t);
                if (value == null || "".equals(value)|| ObjectUtil.isEmpty(value)) {
                    continue;
                }
                if(NumberUtil.isNumber( value.toString())){
                  double temp=  Double.parseDouble(value.toString());
                    if(NumberUtil.compare( temp,0)==0){
                        continue;
                    }

                }
                if (f.getAnnotation(UpperCase.class) != null) {
                    value = value.toString().toUpperCase();
                }
                if(f.getAnnotation(GeometryField.class)!=null){
                    System.out.println(value);
                }
                ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                if (columnCache != null) {
                    queryWrapper.eq(columnCache.getColumn(), value);
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return queryWrapper;
    }


    /**
     * 构建条件查询，如果对象属性值不为空，则添加到where条件中：string-->like，其他-->eq
     *
     * @param t
     * @return
     */
    private QueryWrapper<T> getLikeQueryWrapper(T t) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        List<Field> fields = this.getWrapperField(t);
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(t.getClass());
        for (Field f : fields) {
            try {
                f.setAccessible(true);
                Object value = f.get(t);
                if (value == null || "".equals(value)) {
                    continue;
                }
                if (f.getAnnotation(UpperCase.class) != null) {
                    value = value.toString().toUpperCase();
                }
                ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                if (columnCache != null) {
                    if (f.getType() == String.class) {
                        //租户字段精确查询
                        if (f.getAnnotation(TableMultiId.class) != null) {
                            if (f.getAnnotation(TableLikeField.class) != null) {
                                queryWrapper.like(columnCache.getColumn(), value);
                            } else {
                                queryWrapper.eq(columnCache.getColumn(), value);
                            }
                        } else {
                            queryWrapper.like(columnCache.getColumn(), value);
                        }
                    } else {
                        queryWrapper.eq(columnCache.getColumn(), value);
                    }
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return queryWrapper;
    }

    private List<Field> getWrapperField(Object t) {
        List<Field> fields = new ArrayList<>();
        for (Class clazz = t.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        }
        return fields;
    }

    private UpdateWrapper<T> getUpdateWrapper(T t, boolean isMultiId) {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(t.getClass());
        List<Field> fields = this.getWrapperField(t);
        for (Field f : fields) {
            try {
                f.setAccessible(true);
                Object value = f.get(t);
//                if (value == null || "".equals(value)) {
//                    continue;
//                }
                if ("serialVersionUID".equalsIgnoreCase(f.getName())) {
                    continue;
                }
                if (isMultiId) {
                    TableMultiId tableMultiId = f.getAnnotation(TableMultiId.class);
                    if (tableMultiId != null) {
                        if (value != null && !"".equals(value)) {
                            if (f.getAnnotation(UpperCase.class) != null) {
                                value = value.toString().toUpperCase();
                            }
                            updateWrapper.eq(tableMultiId.value(), value);
                        }
                    } else {
                        ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                        TableField tableField = f.getAnnotation(TableField.class);
                        if (tableField != null) {
                            //@TableField(exist = true)
                            //@TableField(fill = FieldFill.UPDATE)
                            if (tableField.exist() && FieldFill.UPDATE.name().equals(tableField.fill().name())) {
                                updateWrapper.set(columnCache.getColumn(), LocalDateTime.now());
                            }
                        } else {
                            if (value != null && !"".equals(value)) {
                                if (f.getAnnotation(UpperCase.class) != null) {
                                    value = value.toString().toUpperCase();
                                }
                                updateWrapper.set(columnCache.getColumn(), value);
                            }
                        }
                    }
                } else {
                    TableId tableId = f.getAnnotation(TableId.class);
                    if (tableId != null) {
                        if (value != null && !"".equals(value)) {
                            if (f.getAnnotation(UpperCase.class) != null) {
                                value = value.toString().toUpperCase();
                            }
                            updateWrapper.eq(tableId.value(), value);
                        }
                    } else {
                        ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                        TableField tableField = f.getAnnotation(TableField.class);
                        if (tableField != null) {
                            //@TableField(exist = true)
                            //@TableField(fill = FieldFill.UPDATE)
                            if (tableField.exist() && FieldFill.UPDATE.name().equals(tableField.fill().name())) {
                                updateWrapper.set(columnCache.getColumn(), LocalDateTime.now());
                            }
                        } else {
                            if (value != null && !"".equals(value)) {
                                if (f.getAnnotation(UpperCase.class) != null) {
                                    value = value.toString().toUpperCase();
                                }
                                updateWrapper.set(columnCache.getColumn(), value);
                            }
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return updateWrapper;
    }

    public String getLocalUserId() {

        return SecurityUtils.getUserId();
    }


}